using DapperExtensionsNew.Configuration;
using DapperExtensionsNew.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace DapperExtensionsNew.Queryable.Analyzers
{
	public class Range : Where
	{
		protected static readonly string Suffix = "Range";

		protected override bool IsSatisfied(Context context, PropertyInfo queryProperty)
		{
			if (!queryProperty.Name.EndsWith(Suffix))
			{
				return false;
			}
			string targetModelPropertyName = queryProperty.Name.Substring(0, queryProperty.Name.Length - Suffix.Length);
			Type propertyType = queryProperty.PropertyType;
			if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Range<>))
			{
				Type type = propertyType.GetGenericArguments().First();
				if (!(type == typeof(int)) && !(type == typeof(decimal)) && !(type == typeof(DateTime)))
				{
					return false;
				}
				PropertyInfo propertyInfo = context.ModelProperties.FirstOrDefault((PropertyInfo x) => x.Name == targetModelPropertyName);
				if (propertyInfo == null)
				{
					return false;
				}
				Type propertyType2 = propertyInfo.PropertyType;
				if (propertyType2 == type)
				{
					return true;
				}
				if (propertyType2.IsGenericType && propertyType2.GetGenericTypeDefinition() == typeof(Nullable<>))
				{
					return propertyType2.GetGenericArguments().First() == type;
				}
			}
			return false;
		}

		protected override Expression GetWhereClause(Context context, PropertyInfo queryProperty)
		{
			string targetModelPropertyName = queryProperty.Name.Substring(0, queryProperty.Name.Length - Suffix.Length);
			Type type = context.ModelProperties.FirstOrDefault((PropertyInfo x) => x.Name == targetModelPropertyName)?.PropertyType;
			if (type == null)
			{
				throw new ArgumentException("ModelProperties Not Exist Range Name ");
			}
			if (type.IsGenericType)
			{
				type = type.GetGenericArguments().First();
			}
			string columnName = GetColumnName(context.ModelType, targetModelPropertyName);
			SqlDatabaseOptions sqlDatabaseOptions = SqlDatabaseOptionsFactory.GetSqlDatabaseOptions(context.Analyzer);
			string startDelimiter = sqlDatabaseOptions.StartDelimiter;
			string endDelimiter = sqlDatabaseOptions.EndDelimiter;
			Type type2 = typeof(Range<>).MakeGenericType(type);
			Type type3 = typeof(Nullable<>).MakeGenericType(type);
			PropertyInfo property = type3.GetProperty("HasValue") ?? throw new InvalidOperationException();
			PropertyInfo property2 = type3.GetProperty("Value") ?? throw new InvalidOperationException();
			MemberExpression memberExpression = Expression.Property(context.QueryExpression, queryProperty);
			MemberExpression memberExpression2 = Expression.Property(memberExpression, type2.GetProperty("Left", type3) ?? throw new InvalidOperationException());
			MemberExpression test = Expression.Property(memberExpression, type2.GetProperty("LeftExclusive") ?? throw new InvalidOperationException());
			MemberExpression memberExpression3 = Expression.Property(memberExpression, type2.GetProperty("Right", type3) ?? throw new InvalidOperationException());
			MemberExpression test2 = Expression.Property(memberExpression, type2.GetProperty("RightExclusive") ?? throw new InvalidOperationException());
			List<Expression> list = new List<Expression>();
			Expression stringParam = ConcatExpression(Expression.Condition(test, Expression.Constant(" AND " + startDelimiter + columnName + endDelimiter + " > "), Expression.Constant(" AND " + startDelimiter + columnName + endDelimiter + " >= ")), Expression.Constant("@" + columnName + "Left"));
			BlockExpression ifTrue = Expression.Block(CallStringBuilderAppend(context.SqlExpression, stringParam), CallAddParameters(context.ParametersExpression, Expression.Constant("@" + columnName + "Left"), Expression.Property(memberExpression2, property2)));
			list.Add(Expression.IfThen(Expression.AndAlso(Expression.NotEqual(memberExpression2, Expression.Constant(null)), Expression.Property(memberExpression2, property)), ifTrue));
			Expression stringParam2 = ConcatExpression(Expression.Condition(test2, Expression.Constant(" AND " + startDelimiter + columnName + endDelimiter + " < "), Expression.Constant(" AND " + startDelimiter + columnName + endDelimiter + " <= ")), Expression.Constant("@" + columnName + "Right"));
			BlockExpression ifTrue2 = Expression.Block(CallStringBuilderAppend(context.SqlExpression, stringParam2), CallAddParameters(context.ParametersExpression, Expression.Constant("@" + columnName + "Right"), Expression.Property(memberExpression3, property2)));
			list.Add(Expression.IfThen(Expression.AndAlso(Expression.NotEqual(memberExpression3, Expression.Constant(null)), Expression.Property(memberExpression3, property)), ifTrue2));
			return Expression.IfThen(Expression.NotEqual(memberExpression, Expression.Constant(null)), Expression.Block(list));
		}
	}
}
